package com.example.server.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.server.web.domain.Class;
import com.example.server.web.domain.RespBean;
import com.example.server.web.domain.Role;
import com.example.server.web.domain.Student;
import com.example.server.web.domain.SysUser;
import com.example.server.web.domain.page.PageQueryDto;
import com.example.server.web.domain.dto.SysUserDto;
import com.example.server.web.domain.dto.UserLoginParam;
import com.example.server.web.domain.vo.SysUserVo;
import com.example.server.web.exception.CustomException;
import com.example.server.web.mapper.SysUserMapper;
import com.example.server.web.service.ClassService;
import com.example.server.web.service.StudentService;
import com.example.server.web.service.SysUserService;
import com.example.server.web.service.UserRoleService;
import com.example.server.web.utils.JwtTokenUtil;
import com.example.server.web.utils.MyObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 作者
 * @since 2023-04-04
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private StudentService studentService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Value("${CaptchaOnOff.enabled}")
    private boolean CaptchaOnOffEnabled;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private ClassService classService;

    @Override
    public RespBean login(UserLoginParam userLoginParam) {
        //判断验证码开关是否打开
        if(CaptchaOnOffEnabled){
            //根据uuid获得验证码
            String code = (String) redisTemplate.opsForValue().get(userLoginParam.getUuid());
            if(!StringUtils.isNotBlank(code)){
                return RespBean.error("验证码已过期，请重新获取！");
            }

            if(!StringUtils.isNotBlank(userLoginParam.getCode())){
                return RespBean.error("请输入验证码");
            }

            if(!code.equalsIgnoreCase(userLoginParam.getCode())){
                return RespBean.error("验证码输入错误");
            }
        }


        //根据用户名得到用户信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(userLoginParam.getUsername());
        //判断密码是否正确还有判断用户名是否正确
        if(userDetails==null||!passwordEncoder.matches(userLoginParam.getPassword(), userDetails.getPassword())){
            return RespBean.error("用户名或密码不正确！");
        }
        if(!userDetails.isEnabled()){
            return RespBean.error("账号被禁用，请联系管理员！");
        }

        // 更新security登录用户对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        //【把登录的用户对象放到SpringSecurity全局中】
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        //返回令牌
        String token = jwtTokenUtil.generateToken(userDetails);

        SysUser user = new SysUser();
        BeanUtils.copyProperties(userDetails,user);

        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("tokenHead",tokenHead);
        map.put("user",user);

        redisTemplate.delete(userLoginParam.getUuid());
        return RespBean.success("登陆成功",map);
    }

    @Override
    public SysUser getUserByUserName(String username) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername,username);
        return this.getOne(wrapper);
    }

    @Override
    public List<Role> getRolesByUserId(Long userId) {
        return userRoleService.getRolesByUserId(userId);
    }

    @Override
    public Map getUsersPage(PageQueryDto pageQueryDto) {
        String username = "";
        String sex = " ";
        Integer enabled = null;
        Integer page = pageQueryDto.getPage();
        Integer limit = pageQueryDto.getLimit();
        username = (String) pageQueryDto.getParams("username");
        String name = (String) pageQueryDto.getParams("name");
        sex = (String) pageQueryDto.getParams("sex");
        enabled = (Integer) pageQueryDto.getParams("enabled");

        Page<SysUser> p = new Page<>(page,limit);
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username),SysUser::getName,username)
                .like(StringUtils.isNotBlank(name),SysUser::getName,name)
                .eq(StringUtils.isNotBlank(sex),SysUser::getSex,sex)
                .eq(enabled != null,SysUser::getEnabled,enabled);
        userMapper.selectPage(p,queryWrapper);
        List<SysUser> users = p.getRecords();
        //获得用户的角色列表
        List<SysUserVo> userVos = new ArrayList<>();
        for (SysUser user : users) {
            SysUserVo sysUserVo = new SysUserVo();
            List<Role> roles = getRolesByUserId(user.getId());
            //复制属性
            BeanUtils.copyProperties(user,sysUserVo);
            sysUserVo.setRoles(roles);
            userVos.add(sysUserVo);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("list",userVos);
        map.put("total",p.getTotal());
        return map;
    }


    @Override
    public SysUser getUserById(Long userId) {
        if(userId==null){
            throw new CustomException("用户id不能为空");
        }
        SysUser user = userMapper.selectById(userId);
        if(user==null){
            throw new CustomException("该用户不存在");
        }
        return user;
    }

    @Override
    public Page<SysUser> getUsersByRole(PageQueryDto pageQueryDto) {
        String username = "";
        String name = " ";
        Integer roleId = null;
        Integer classId = null;
        Integer page = pageQueryDto.getPage();
        Integer limit = pageQueryDto.getLimit();

        username = (String) pageQueryDto.getParams("username");
        name = (String) pageQueryDto.getParams("name");
        roleId =  pageQueryDto.getParams("roleId") != null ? (Integer) pageQueryDto.getParams("roleId") : 20020314;
        classId= pageQueryDto.getParams("classId") != null ? (Integer) pageQueryDto.getParams("classId") : 20020314;
        Page<SysUser> p = new Page<>(page,limit);

        p.setRecords(userMapper.getUsersByRole((page-1)*limit,limit,roleId.longValue(),username,name, Long.valueOf(classId)) );
        p.setTotal(userMapper.getTotal(Long.valueOf(roleId),username,name, Long.valueOf(classId)));
        return p;
    }


    @Transactional
    @Override
    public Integer insertUser(SysUserDto sysUserDto) {
        //判断是否为空
        String username = sysUserDto.getUsername();
        if (!StringUtils.isNotBlank(username)){
            throw new CustomException("用户账号（学号/工号）不能为空");
        }
        if (!StringUtils.isNotBlank(sysUserDto.getSex())){
            throw new CustomException("性别不能为空");
        }
        if (sysUserDto.getAge() == null){
            throw new CustomException("年龄不能为空");
        }

        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername,username);
        SysUser user2 = this.getOne(wrapper);
        //判断用户账号（学号）是否已存在
        if( user2!=null){
            throw new CustomException("用户账号（学号/工号）已存在");
        }
        SysUser sysUser = new SysUser();
        //bean复制属性
        BeanUtils.copyProperties(sysUserDto,sysUser);
        //加密密码
        String encodePass = passwordEncoder.encode("123456");
        sysUser.setPassword(encodePass);
        //插入数据
        int i = userMapper.insert(sysUser);
        List<Long> roleIds = sysUserDto.getRoleIds();
        //插入用户所对应的角色
        userRoleService.insertUserRoles(sysUser.getId(),roleIds);
        return i;
    }

    @Transactional
    @Override
    public Integer updateUser(SysUserDto sysUserDto,Boolean isVailPass) {
        String username = sysUserDto.getUsername();
        if (!StringUtils.isNotBlank(username)){
            throw new CustomException("用户账号（学号/工号）不能为空");
        }
        if (!StringUtils.isNotBlank(sysUserDto.getSex())){
            throw new CustomException("性别不能为空");
        }
        if (sysUserDto.getAge() == null){
            throw new CustomException("年龄不能为空");
        }
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getId,sysUserDto.getId());
        SysUser user2 = this.getOne(wrapper);
        //判断用户账号是否修改
        if(!user2.getUsername().equals(sysUserDto.getUsername())){
            throw new CustomException("不能修改用户账号（学号/工号）");
        }

        //判断用户密码是否被修改
        if (isVailPass && !(user2.getPassword()).equals(sysUserDto.getPassword())){
            throw new CustomException("密码不能修改");
        }

        SysUser sysUser = new SysUser();
        //Bean复制属性
        BeanUtils.copyProperties(sysUserDto,sysUser);
        //更新用户信息
        int i = userMapper.updateById(sysUser);
        //更新用户的角色
        userRoleService.updateUserRoles(sysUserDto.getId(),sysUserDto.getRoleIds());
        return i;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer deleteUser(Long userId) {
        if(userId==null){
            throw new CustomException("用户id不能为空");
        }
        userRoleService.deleteUserRoles(userId);
        int i = userMapper.deleteById(userId);
        //判断是否是学生角色，若是学生角色，则删除学生信息
        List<Long> ids = new ArrayList<>();
        ids.add(userId);
        removeStuInfo(ids);
        return i;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer deleteUsers(List<Long> userIdList) {
        if(userIdList==null){
            throw new CustomException("用户id不能为空");
        }
        removeStuInfo(userIdList);
        return userMapper.deleteBatchIds(userIdList);
    }

    @Override
    public String uploadPhoto(Long userId, String fileName) {
        userMapper.uploadPhoto(userId,fileName);
        return null;
    }

    @Override
    public boolean initPassword(Long id) {
        if(id == null){
            throw new CustomException("用户id不能为空");
        }
        String encode = passwordEncoder.encode("123456");
        LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(SysUser::getPassword,encode);
        wrapper.eq(SysUser::getId,id);
        return this.update(wrapper);

    }

    /**
     * 公共方法：删除学生，同时删除学生表的数据
     * @Param
     */
    public void removeStuInfo(List<Long> userIds){
        if (CollectionUtils.isEmpty(userIds)){
            return;
        }
        for (Long userId : userIds) {
            //先查询此用户是不是学生
            LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Student::getUserId,userId);
            Student student = studentService.getOne(wrapper);
            //若此用户不是学生则跳过
            if (ObjectUtils.isNull(student)){
                continue;
            }
            //若角色是学生，则删除学生
            //获取班级id
            Long classId = student.getClassId();
            if (classId != null){
                Class aClass = classService.getById(classId);
                if (MyObjectUtils.isNotNull(aClass)){
                    //班级人数减一
                    LambdaUpdateWrapper<Class> classWrapper = new LambdaUpdateWrapper<>();
                    classWrapper.eq(Class::getId,classId);
                    classWrapper.set(Class::getClassPersonNum,aClass.getClassPersonNum()-1);
                    classService.update(classWrapper);
                }
            }
            //删除学生
            studentService.removeById(student.getId());
        }
    }
}
